#include "AppException.hh"

#include <ctime>
#include <sstream>
#include <fstream>

// (static - common to all exceptions) Enable/disable logging
bool				AppException::mLog = true;

// (static - common to all exceptions) Stream where exceptions will be logged
std::ofstream			AppException::mOutputStream;

// @author rannou_s
// @param line	line where the error was raised
// @param file	file where the error was raised
//
// At creation, catch the date and log the exception into mOutputStream
// This is the only available constructor (assuming there's a macro to use it without
// having to set __LINE__ and __FILE__ each time we use it.

AppException::AppException(int line, const char *file): mLine(line), mFile(file)
{
  mDate = this->getDate();
  this->buildDiag();
  this->log();
}

AppException::~AppException(void) throw()
{
  ;
}

AppException::AppException(const AppException & e)
{
  *this = e;
}

AppException &			AppException::operator=(const AppException & e)
{
  mLine = e.mLine;
  mFile = e.mFile;
  mDate = e.mDate;
  mDiag = e.mDiag;
  return *this;
}

const	char *			AppException::what(void) const throw()
{
  return "Unspecified error raised";
}

// @author rannou_s
// returns a formated string of the current date/time, stripping \n

std::string			AppException::getDate(void) const
{
  std::time_t	now = time(0);
  std::string	result(std::ctime(&now));
  size_t	offset = result.find_first_of('\n');

  if (offset > 0)
    {
      result.erase(offset);
    }
  return result;
}

// @author rannou_s
// Log the diagnostic if mLog is enabled and if mOutputStream is openned

void				AppException::log(void) const
{
  if (AppException::mLog == true && AppException::mOutputStream.is_open() == true)
    {
      mOutputStream << mDiag << std::endl;
    }
}

// @author rannou_s
// Print a diagnostic on stdout

void				AppException::dump(void) const
{
  std::cout << mDiag << std::endl;
}

// @author rannou_s
// Returns a char * describing the exception in the following fmt:
// date/time - file.cpp:42 - [exception raised] what?

void				AppException::buildDiag(void)
{
  std::ostringstream		out;
  
  out << mDate << " - " << mFile << ":" << mLine << " - [exception raised] " << this->what();
  mDiag = out.str();
}

// @author rannou_s
// Activate logging if off

void				AppException::activateLog()
{
  if (AppException::mLog == false)
    {
      AppException::mLog = !AppException::mLog;
    }
}

// @author rannou_s
// Desctivate logging if on

void				AppException::desactivateLog()
{
  if (AppException::mLog == true)
    {
      AppException::mLog = !AppException::mLog;
    }
}

// @author rannou_s
// @param file		file where exceptions will be logged
// Close the previous oppened file if already opened, and open the file pointed by file

void				AppException::setLogFile(const char * file)
{
  if (AppException::mOutputStream.is_open() == true)
    {
      AppException::mOutputStream.close();
    }
  AppException::mOutputStream.open(file, std::ios::app);
}

// @author rannou_s
// Returns a diagnostic

std::ostream &			operator<<(std::ostream & o, const AppException & e)
{
  o << e.mDiag;
  return o;
}
